1   /*
2    * Copyright (C) 2007 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import com.google.common.annotations.GwtCompatible;
20  import com.google.common.annotations.GwtIncompatible;
21  
22  import java.io.IOException;
23  import java.io.ObjectInputStream;
24  import java.io.ObjectOutputStream;
25  import java.util.LinkedHashMap;
26  
27  /**
28   * A {@code Multiset} implementation with predictable iteration order. Its
29   * iterator orders elements according to when the first occurrence of the
30   * element was added. When the multiset contains multiple instances of an
31   * element, those instances are consecutive in the iteration order. If all
32   * occurrences of an element are removed, after which that element is added to
33   * the multiset, the element will appear at the end of the iteration.
34   * 
35   * <p>See the Guava User Guide article on <a href=
36   * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Multiset">
37   * {@code Multiset}</a>.
38   *
39   * @author Kevin Bourrillion
40   * @author Jared Levy
41   * @since 2.0 (imported from Google Collections Library)
42   */
43  @GwtCompatible(serializable = true, emulated = true)
44  @SuppressWarnings("serial") // we're overriding default serialization
45  public final class LinkedHashMultiset<E> extends AbstractMapBasedMultiset<E> {
46  
47    /**
48     * Creates a new, empty {@code LinkedHashMultiset} using the default initial
49     * capacity.
50     */
51    public static <E> LinkedHashMultiset<E> create() {
52      return new LinkedHashMultiset<E>();
53    }
54  
55    /**
56     * Creates a new, empty {@code LinkedHashMultiset} with the specified expected
57     * number of distinct elements.
58     *
59     * @param distinctElements the expected number of distinct elements
60     * @throws IllegalArgumentException if {@code distinctElements} is negative
61     */
62    public static <E> LinkedHashMultiset<E> create(int distinctElements) {
63      return new LinkedHashMultiset<E>(distinctElements);
64    }
65  
66    /**
67     * Creates a new {@code LinkedHashMultiset} containing the specified elements.
68     *
69     * <p>This implementation is highly efficient when {@code elements} is itself
70     * a {@link Multiset}.
71     *
72     * @param elements the elements that the multiset should contain
73     */
74    public static <E> LinkedHashMultiset<E> create(
75        Iterable<? extends E> elements) {
76      LinkedHashMultiset<E> multiset =
77          create(Multisets.inferDistinctElements(elements));
78      Iterables.addAll(multiset, elements);
79      return multiset;
80    }
81  
82    private LinkedHashMultiset() {
83      super(new LinkedHashMap<E, Count>());
84    }
85  
86    private LinkedHashMultiset(int distinctElements) {
87      // Could use newLinkedHashMapWithExpectedSize() if it existed
88      super(new LinkedHashMap<E, Count>(Maps.capacity(distinctElements)));
89    }
90  
91    /**
92     * @serialData the number of distinct elements, the first element, its count,
93     *     the second element, its count, and so on
94     */
95    @GwtIncompatible("java.io.ObjectOutputStream")
96    private void writeObject(ObjectOutputStream stream) throws IOException {
97      stream.defaultWriteObject();
98      Serialization.writeMultiset(this, stream);
99    }
100 
101   @GwtIncompatible("java.io.ObjectInputStream")
102   private void readObject(ObjectInputStream stream)
103       throws IOException, ClassNotFoundException {
104     stream.defaultReadObject();
105     int distinctElements = Serialization.readCount(stream);
106     setBackingMap(new LinkedHashMap<E, Count>(
107         Maps.capacity(distinctElements)));
108     Serialization.populateMultiset(this, stream, distinctElements);
109   }
110 
111   @GwtIncompatible("not needed in emulated source")
112   private static final long serialVersionUID = 0;
113 }